//
// Copyright (c) 2009 All Right Reserved
//
// vl
//
// 2009-02-01
//
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Xml.Serialization;
using JetBrains.Annotations;
using LargoCommon.Abstract;
using LargoCommon.Interfaces;
using LargoCommon.Localization;
namespace LargoCommon.Music
{
///
/// Musical Element.
///
public class MusicalElement : IAbstractElement
{
#region Fields
////
//// Last Used Bit.
////
//// private int lastUsedBit;
/// Complete list of all tones in musical part.
private MusicalStrikeCollection musicalTones;
#endregion
#region Constructors
///
/// Initializes a new instance of the class. Unused.
///
public MusicalElement() {
this.Status = new LineStatus();
this.IsLive = true;
this.IsComposed = true;
}
///
/// Initializes a new instance of the class.
///
/// The given status.
/// The given previous element.
public MusicalElement(LineStatus givenStatus, MusicalElement givenPreviousElement) {
this.Status = (LineStatus)givenStatus.Clone(); //// !!!!
this.PreviousElement = givenPreviousElement;
this.IsLive = true;
this.IsComposed = true;
}
///
/// Initializes a new instance of the class.
///
/// The element.
/// The header.
public MusicalElement(XElement xelement, MusicalHeader header) : this() {
Contract.Requires(xelement != null);
if (xelement == null) {
return;
}
this.Status = new LineStatus(xelement.Element("Status"), header);
}
#endregion
#region Properties - Xml
/// Gets Xml representation.
/// Property description.
public virtual XElement GetXElement {
get {
XElement xelement = new XElement("Element");
if (this.Bar == null || this.Line == null) {
return xelement;
}
xelement.Add(new XAttribute("Bar", this.Bar.BarNumber));
xelement.Add(new XAttribute("LineIndex", this.Line.LineIndex));
var xstatus = this.Status.GetXElement;
xelement.Add(xstatus);
if (this.Tones != null && this.Tones.Count > 0) {
var xtones = this.Tones.GetXElement;
xelement.Add(xtones);
}
return xelement;
}
}
#endregion
#region Properties
///
/// Gets or sets the bar.
///
///
/// The bar.
///
public IAbstractBar Bar { get; set; }
///
/// Gets or sets the track.
///
///
/// The track.
///
public IAbstractLine Line { get; set; }
/// Gets the musical line.
/// The musical line.
public MusicalLine MusicalLine => (MusicalLine)this.Line;
///
/// Gets the point.
///
///
/// The point.
///
public MusicalPoint Point {
get {
if (this.Line == null || this.Bar == null) {
return new MusicalPoint(0, 0);
}
return new MusicalPoint(this.Line.LineIndex, this.Bar.BarNumber);
}
}
///
/// Gets or sets Current Musical Track Status.
///
public LineStatus Status { get; set; }
///
/// Gets or sets a value indicating whether this instance is mute.
///
///
/// True if this instance is mute; otherwise, false.
///
public bool IsLive { get; set; } //// private set
///
/// Gets or sets a value indicating whether this instance is composed.
///
///
/// True if this instance is composed; otherwise, false.
///
public bool IsComposed { get; set; } //// private set
///
/// Gets or sets a value indicating whether this instance is finished = composed.
///
///
/// true if this instance is finished; otherwise, false.
///
public bool IsFinished { get; set; } //// private set
///
/// Gets or sets the previous bar track.
///
///
/// The previous bar track.
///
public MusicalElement PreviousElement { get; set; }
///
/// Gets or sets the previous bar track.
///
///
/// The previous bar track.
///
public MusicalElement NextElement { get; set; }
///
/// Gets or sets the musical tones.
///
///
/// The musical tones.
///
[XmlIgnore]
public MusicalStrikeCollection Tones {
get {
Contract.Ensures(Contract.Result() != null);
return this.musicalTones ?? (this.musicalTones = new MusicalStrikeCollection());
}
set => this.musicalTones = value;
}
/// Gets last but one melodic tone.
/// Property description.
/// [XmlIgnore]
// ReSharper disable once UnusedAutoPropertyAccessor.Local
public MusicalTone PreviousBarFirstTone { get; private set; }
///
/// Gets or sets the tone packets - detail info about all tones in the element - for tracing;
///
///
/// Returns value.
///
public TonePacket TonePacket { get; set; }
#endregion
///
/// Gets or sets the text.
///
///
/// The text.
///
public string DisplayText { get; set; }
///
/// Gets or sets the tool tip.
///
///
/// The tool tip.
///
public string ToolTip { get; set; }
///
/// Gets or sets a value indicating whether this instance has content.
///
///
/// true if this instance has content; otherwise, false.
///
public bool HasContent { get; set; }
///
/// Gets or sets the type of the content.
///
///
/// The type of the content.
///
public EditorContent ContentType { get; set; }
#region Identifiers
///
/// Gets the main identifiers.
///
///
/// The main identifiers.
///
public IList Identifiers {
get {
var items = new List();
var item = new KeyValuePair("Line type", this.Line.FirstStatus.LineType.ToString());
items.Add(item);
item = new KeyValuePair("Line number", this.Line.LineNumber.ToString());
items.Add(item);
item = new KeyValuePair("Bar number", this.Bar.BarNumber.ToString());
items.Add(item);
var status = this.Status;
if (status == null) {
return items;
}
item = new KeyValuePair(
LocalizedMusic.String("LocalPurpose"),
LocalizedMusic.String(status.LocalPurpose.ToString()));
items.Add(item);
item = new KeyValuePair("Instrument", status.Instrument.ToString());
items.Add(item);
if (status.RhythmicStructure != null) {
item = new KeyValuePair(
LocalizedMusic.String("Rhythmic structure"), status.RhythmicStructure.ElementString());
items.Add(item);
if (status.RhythmicStructure.Level == 1 && status.RhythmicStructure.ToneLevel == 0) {
return items;
}
}
item = new KeyValuePair(LocalizedMusic.String("Loudness"), LocalizedMusic.String("Loud" + ((int)status.Loudness).ToString()));
items.Add(item);
if (status.IsMelodic) {
item = new KeyValuePair(LocalizedMusic.String("Octave"), LocalizedMusic.String("Octave" + ((int)status.Octave).ToString()));
items.Add(item);
item = new KeyValuePair(LocalizedMusic.String("Melodic shape"), LocalizedMusic.String("MelodicShape" + ((int)status.MelodicShape).ToString()));
items.Add(item);
item = new KeyValuePair(LocalizedMusic.String("Melodic function"), LocalizedMusic.String("MelodicFunction" + ((int)status.MelodicFunction).ToString()));
items.Add(item);
if (status.MelodicStructure != null) {
item = new KeyValuePair(
LocalizedMusic.String("Melodic structure"), status.MelodicStructure.ElementString());
items.Add(item);
}
item = new KeyValuePair(LocalizedMusic.String("Band"), LocalizedMusic.String("Band" + ((int)status.BandType).ToString()));
items.Add(item);
item = new KeyValuePair(LocalizedMusic.String("Tone level"), status.ToneLevel.ToString(CultureInfo.InvariantCulture));
items.Add(item);
item = new KeyValuePair(LocalizedMusic.String("Beat level"), status.BeatLevel.ToString(CultureInfo.InvariantCulture));
items.Add(item);
item = new KeyValuePair(LocalizedMusic.String("Priority"), status.Priority.ToString());
items.Add(item);
}
/* Unused - not ready - identifiers
item = new KeyValuePair(LocalizedMusic.String("Melodic direction"),
this.MelodicDirection.ToString(CultureInfo.InvariantCulture));
items.Add(item);
item = new KeyValuePair(LocalizedMusic.String("Melodic genus"), this.MelodicGenus.ToString());
items.Add(item);
item = new KeyValuePair(LocalizedMusic.String("Rhythmic tension"), this.RhythmicTension.ToString(CultureInfo.InvariantCulture));
items.Add(item);
*/
return items;
}
}
#endregion
///
/// Determines whether [is compatible with] [the specified given musical unit].
///
/// The given element.
///
/// true if [is compatible with] [the specified given musical unit]; otherwise, false.
///
public bool IsCompatibleWith(MusicalElement givenElement) {
return this.HasContent && givenElement.DisplayText == this.DisplayText;
}
#region Public methods
/// Makes a deep copy of the MusicalElement object.
/// Returns object.
public object Clone() {
var element = new MusicalElement {
Bar = this.Bar,
Line = this.Line,
Status = (LineStatus)this.Status.Clone(),
Tones = this.Tones.Clone(true)
};
//// 2016/08
return element;
}
///
/// Sets the tones.
///
/// The given tones.
public void SetTones(MusicalStrikeCollection givenTones) {
this.Tones = givenTones;
}
///
/// Prepares the tone packets.
///
public void PrepareTonePacket() {
this.TonePacket = new TonePacket(this.Tones);
}
///
/// Prepares the content.
///
/// Type of the given content.
public void PrepareContent(EditorContent givenContentType) {
this.DisplayText = string.Empty;
this.ToolTip = null;
this.HasContent = false;
var status = this.Status;
if (!status.HasContent) {
return;
}
this.ContentType = givenContentType;
switch (givenContentType) {
case EditorContent.Cell: {
var sb = new StringBuilder();
if (status?.ToneLevel > 0 || status?.MelodicFunction != MelodicFunction.None) { //// || status?.MelodicShape != MelodicShape.None
sb.AppendLine(status?.ToneLevel.ToString() + " " + status?.MelodicShape.ToString());
sb.Append(status?.MelodicFunction.ToString());
}
this.DisplayText = sb.ToString(); //// this.Point.ToString();
this.ToolTip = status.GetTooltip;
break;
}
case EditorContent.RhythmicStructure: {
this.DisplayText = status.RhythmicStructure != null ? status.RhythmicStructure.ElementSchema : string.Empty;
this.ToolTip = status.GetTooltip;
break;
}
case EditorContent.MelodicStructure: {
this.DisplayText = status.MelodicStructure != null ? status.MelodicStructure.ElementSchema : string.Empty;
this.ToolTip = status.GetTooltip;
break;
}
case EditorContent.MelodicFunction: {
this.DisplayText = status.MelodicFunction.ToString();
this.ToolTip = status.GetTooltip;
break;
}
case EditorContent.Loudness: {
this.DisplayText = status.Loudness.ToString();
this.ToolTip = status.GetTooltip;
break;
}
case EditorContent.RhythmicMotive: {
this.DisplayText = status.RhythmicMotive != null ? status.RhythmicMotive.Name : string.Empty;
this.ToolTip = status.GetTooltip;
break;
}
case EditorContent.MelodicMotive: {
this.DisplayText = status.MelodicMotive != null ? status.MelodicMotive.Name : string.Empty;
this.ToolTip = status.GetTooltip;
break;
}
case EditorContent.Band: {
this.DisplayText = status.BandType.ToString();
this.ToolTip = status.GetTooltip;
break;
}
case EditorContent.Octave: {
this.DisplayText = status.Octave.ToString();
this.ToolTip = status.GetTooltip;
break;
}
case EditorContent.Instrument: {
this.DisplayText = status.Instrument.ToString();
this.ToolTip = status.GetTooltip;
break;
}
case EditorContent.BeatLevel: {
this.DisplayText = status.BeatLevel.ToString();
this.ToolTip = status.GetTooltip;
break;
}
case EditorContent.ToneLevel: {
this.DisplayText = status.ToneLevel.ToString();
this.ToolTip = status.GetTooltip;
break;
}
case EditorContent.MelodicShape: {
this.DisplayText = status.MelodicShape.ToString();
this.ToolTip = status.GetTooltip;
break;
}
}
this.HasContent = true;
}
///
/// Sets the melodic pattern.
///
/// The given pattern.
/// The given line.
/// if set to true [keep original arrange].
[UsedImplicitly]
public void EditorSetMelodicPattern(MelodicPattern givenPattern, byte givenLine, bool keepOriginalArrange) {
if (givenLine >= givenPattern.Voices.Count) {
return;
}
var voice = givenPattern.Voices[givenLine];
this.Tones = voice.Tones;
this.Status.System = this.Bar.Header.System;
this.Status.SetMelodicPatternVoice(voice, keepOriginalArrange);
}
///
/// Sets the melodic pattern.
///
/// The given pattern.
/// The given line.
/// if set to true [keep original arrange].
[UsedImplicitly]
public void EditorSetRhythmicPattern(RhythmicPattern givenPattern, byte givenLine, bool keepOriginalArrange) {
if (givenLine >= givenPattern.Voices.Count) {
return;
}
var voice = givenPattern.Voices[givenLine];
this.Tones = voice.Tones;
this.Status.System = this.Bar.Header.System;
this.Status.SetRhythmicPatternVoice(voice, keepOriginalArrange);
}
///
/// Makes the status from tones.
///
public void SetElementStatusFromTones() {
var trackStatus = this.MusicalLine.FirstStatus;
if (this.Status == null || trackStatus == null) {
return;
}
//// Real track properties
this.Status.BarNumber = this.Bar.BarNumber; //// 2018/12
this.Status.MelodicVariety = trackStatus.MelodicVariety;
//// this.Status.Channel = trackStatus.Channel;
this.Status.Staff = trackStatus.Staff;
this.Status.Voice = trackStatus.Voice;
//// this.Status.HarmonicModalization = trackStatus.HarmonicModalization;
//// Problem of repeated reading of MIF file .... ***
if (this.Status.LineType == MusicalLineType.None && trackStatus.LineType != MusicalLineType.None) {
this.Status.LineType = trackStatus.LineType;
}
if (this.Status.LocalPurpose == LinePurpose.None && trackStatus.LocalPurpose != LinePurpose.None) {
this.Status.LocalPurpose = trackStatus.LocalPurpose; //// 2018/12
}
//// ***
var barAllTones = this.Tones;
//// var isMelodic = this.Status.IsMelodic;
//// var barTones = isMelodic ? this.SingleMelodicTones() : null;
var melodicTonesInBar = this.SingleMelodicTones();
if (barAllTones == null || barAllTones.Count == 0) {
return;
}
//// *** Loudness ***
var loudness = melodicTonesInBar.MeanLoudness;
this.Status.Loudness = loudness;
//// *** Rhythmic tension ***
var rstruct = barAllTones.DetermineRhythmicStructure(this.Bar.Header.System.RhythmicOrder);
this.Status.RhythmicStructure = rstruct;
this.Status.ToneLevel = rstruct.ToneLevel;
this.Status.BeatLevel = rstruct.Level;
this.Status.RhythmicTension = (byte)rstruct.FormalBehavior.Variance;
//// Melodic structure in bar - from tones
var isMelodic = this.Status.IsMelodic;
if (isMelodic) {
if (melodicTonesInBar != null && melodicTonesInBar.Any()) {
//// lastMelodicTone
var mstruct = melodicTonesInBar.DetermineMelodicStructure(null, this.Bar.HarmonicBar);
if (mstruct == null) {
var system = new MelodicSystem(1, 1);
mstruct = new MelodicStructure(system, 1);
}
this.Status.MelodicStructure = mstruct;
}
}
//// *** StaffChange ***
var firstTone = barAllTones.FirstOrDefault();
if (firstTone != null) {
this.Status.Staff = firstTone.Staff;
this.Status.Voice = firstTone.Voice;
}
//// 2016/06
//// *** Instrument ***
if (this.Status.Instrument.IsEmpty) {
if (this.Status.LineType == MusicalLineType.Melodic) {
this.Status.Instrument = new MusicalInstrument(barAllTones.FirstMelodicInstrument);
}
if (this.Status.LineType == MusicalLineType.Rhythmic) {
this.Status.Instrument = new MusicalInstrument(barAllTones.FirstRhythmicInstrument);
}
}
//// *** Octaves ***
this.Status.Octave = melodicTonesInBar.MeanOctave;
this.Status.BandType = MusicalProperties.BandTypeFromOctave(this.Status.Octave);
//// 2016/10
if (this.Tones.Count > 0) {
this.Status.MelodicPlan = new MelodicPlan(this.Tones);
}
this.Status.MelodicFunction = melodicTonesInBar.DetermineMelodicType(this.Bar.HarmonicBar);
this.Status.MelodicShape = MelodicShape.Scales;
}
///
/// List of tones in one bar of musical part.
///
///
/// Returns value.
///
public MusicalToneCollection SingleMelodicTones() {
var tones = from mT in this.Tones
where mT.ToneType == MusicalToneType.Melodic && !mT.IsPause
orderby mT.BitFrom
select mT;
var mtc = new MusicalToneCollection();
//// Only one tone of each cluster
var lastBitFrom = -1;
// ReSharper disable once LoopCanBePartlyConvertedToQuery
foreach (var tone in tones) {
MusicalTone mtone = tone as MusicalTone;
if (mtone == null) {
continue;
}
if (mtone.BitFrom == lastBitFrom) {
continue;
}
mtc.Add(mtone);
lastBitFrom = mtone.BitFrom;
}
return mtc;
}
///
/// List of tones in one bar of musical part.
///
/// The bar numbers back.
/// The bar numbers forward.
///
/// Returns value.
///
public MusicalToneCollection MelodicTonesAround(int barNumbersBack, int barNumbersForward) {
var atones = new List();
MusicalElement element = this;
for (int stepDown = 0; stepDown <= barNumbersBack && element != null; stepDown++) {
var mts = this.Tones.Where(x => x != null && x.ToneType == MusicalToneType.Melodic && x.Loudness > 0);
atones.AddRange(mts);
element = element.PreviousElement;
}
element = this;
for (int stepUp = 0; stepUp <= barNumbersForward && element != null; stepUp++) {
var mts = this.Tones.Where(x => x != null && x.ToneType == MusicalToneType.Melodic && x.Loudness > 0);
atones.AddRange(mts);
element = element.NextElement;
}
var distinctTones = new MusicalToneCollection();
foreach (var tone in atones) {
var mt = tone as MusicalTone;
if (mt?.Pitch == null) {
continue;
}
var mt1 = mt;
var ex = from mtone in distinctTones where mtone.Pitch.Element == mt1.Pitch.Element select mtone;
if (!ex.Any()) {
distinctTones.Add(mt);
}
if (distinctTones.Count >= 7) {
break;
}
}
return distinctTones;
}
///
/// Musicals the tone at.
///
/// The tick.
/// The rhythmic structure.
/// Returns value.
public MusicalStrike MusicalToneAt(byte tick, FiguralStructure rhythmicStructure) { //// RhythmicStructure
if (rhythmicStructure == null) {
return null;
}
var level = rhythmicStructure.LevelOfBit(tick);
return (level < this.Tones.Count ? this.Tones[level] : null) as MusicalStrike;
}
#endregion
///
/// Composes from plan.
///
public void ComposeFromPlan() {
this.Status.RhythmicStructure = this.GetRhythmicStructure();
}
/* Compose Rhythm From Plan
st.RhythmicStructure = new RhythmicStructure(header.System.RhythmicSystem, 0);
byte tick = (byte)(systemLength % 12);
if (element.IsEmpty) {
st.RhythmicStructure.SetElement(tick, 2);
}
else {
st.RhythmicStructure.SetElement(tick, 1);
}
st.RhythmicStructure.CompleteFromElements();
st.RhythmicStructure.DetermineToneLevel();
*/
/// Gets rhythmic structure.
/// The rhythmic structure.
public RhythmicStructure GetRhythmicStructure() {
RhythmicSystem rhythmicSystem = this.Bar.Header.System.RhythmicSystem;
string structuralCode = string.Empty;
switch (this.Status.RhythmicFace?.Name) {
case "Regular whole-note": {
structuralCode = "1,23*0";
break;
}
case "Regular half-notes": {
structuralCode = "1,11*0,1,11*0";
break;
}
case "Regular triads": {
structuralCode = "1,7*0,1,7*0,1,7*0";
break;
}
case "Regular quarters": {
structuralCode = "1,5*0,1,5*0,1,5*0,1,5*0";
break;
}
case "Regular sixths": {
structuralCode = "1,3*0,1,3*0,1,3*0,1,3*0,1,3*0,1,3*0";
break;
}
case "Regular eighths": {
structuralCode = "1,2*0,1,2*0,1,2*0,1,2*0,1,2*0,1,2*0,1,2*0,1,2*0";
break;
}
case "Regular twelfths": {
structuralCode = "1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0";
break;
}
case "Empty": {
structuralCode = string.Empty;
break;
}
}
var rs = new RhythmicStructure(rhythmicSystem, structuralCode);
return rs;
}
///
/// Composes the tone.
///
/// The melodic tone.
public void ComposeTone(MusicalTone musicalTone) {
Contract.Requires(musicalTone != null);
Contract.Requires(this.Status != null);
//// Contract.Requires(this.Line.CurrentTone != null);
musicalTone.SetPitch(new MusicalPitch(this.Bar.Header.System.HarmonicSystem));
//// this.HarmonicModality = null;
bool singleHarmony = true; //// 2018/10
var hstruct = this.Bar.HarmonicBar?.PrevailingHarmonicStructure(musicalTone.BitRange, out singleHarmony); //// (musicalBar.Number)
if (hstruct != null && hstruct.Level == 0) {
hstruct = null;
}
var modalization = MusicalSettings.Singleton.HarmonicModalization;
if (modalization == HarmonicModalizationType.Consecutive) { //// != HarmonicModalizationType.Forced
this.Status.HarmonicModality = this.DetermineHarmonicModality(hstruct); //// , this.Status.HarmonicModalization
}
if (modalization == HarmonicModalizationType.Forced) { //// != HarmonicModalizationType.Forced
this.Status.HarmonicModality = MusicalSettings.Singleton.ForcedModality;
}
//// harStruct.SetHarModality(hm);
if (this.Status.HarmonicModality == null) {
return;
}
this.MusicalLine.CurrentTone = musicalTone;
var melodicVariety = this.MusicalLine.FirstStatus.MelodicVariety; //// Status.MelodicVariety;
if (melodicVariety == null) {
return;
}
if (!melodicVariety.GeneratePossibilities(
this.MusicalLine.CurrentTone,
this.Status.HarmonicModality,
hstruct,
this.Status.IsHarmonic && singleHarmony)) {
return;
}
var newMelTone = melodicVariety.OptimalNextMelTone(this.MusicalLine.CurrentTone);
if (!this.Status.IsMelodic) {
return;
}
musicalTone.SetMelTone(newMelTone);
this.CompleteMelodicTone(musicalTone);
}
#region Public methods - Loudness
///
/// Determine loudness of the tone.
///
/// Rhythmical structure.
/// Range of tone.
///
/// Returns value.
///
public MusicalLoudness DetermineLoudness(FiguralStructure rhythmicStruct, BitRange toneRange) {
Contract.Requires(rhythmicStruct != null);
Contract.Requires(toneRange != null);
if (rhythmicStruct == null) {
return 0;
}
//// if (toneRange == null) { return 0; }
if (rhythmicStruct.IsPauseStart(toneRange.BitFrom)) {
return 0;
}
var status = this.Status;
byte loudness;
if (MusicalSettings.Singleton.CorrectLoudness) {
loudness = this.CorrectLoudness(toneRange, (byte)(status != null ? (byte)status.Loudness : 0));
}
else {
loudness = (byte)(status != null ? (byte)status.Loudness : 0);
}
if (status != null && (status.IsMelodicalNature && status.MelodicFunction == MelodicFunction.MelodicMotion
&& MusicalSettings.Singleton.HighlightMelodicVoices)) {
loudness = (byte)Math.Min(loudness + 4, (byte)MusicalLoudness.MaxLoudness);
}
return (MusicalLoudness)loudness;
}
#endregion
#region Public methods - Quantities
/// Prepares current melodic interval.
/// Returns value.
public bool PrepareMelInterval() {
var line = (MusicalLine)this.Line;
if ((line.LastTone != null) && (line.CurrentTone != null) &&
(!line.LastTone.IsEmpty && !line.CurrentTone.IsEmpty)) {
////201508 this.ComposedTrack.TrackEngine
this.Status.CurrentMelInterval = new MelodicInterval(this.Bar.Header.System.HarmonicSystem, line.LastTone.Pitch, line.CurrentTone.Pitch);
return true;
//// this._MelInterval.SetHarmonicProperties();
}
this.Status.CurrentMelInterval = null;
return false;
}
#endregion
#region Public methods - Rhythmic
///
/// Fills the with rhythm.
///
public void FillWithRhythm() {
switch (this.Status?.LocalPurpose) {
case LinePurpose.Composed:
this.FillWithRequestedRhythm();
break;
case LinePurpose.Fixed:
this.FillWithRhythmOfTones(this.Tones); //// 2016 .MusicalTonesInBar(this.Number)//// 2014/01
break;
}
}
///
/// Creates one bar of rhythm in this musical part.
///
/// Rhythmical structure.
/// Musical Loudness.
public void FillWithRhythm(RhythmicStructure rhythmicStruct, MusicalLoudness givenLoudness) {
Contract.Requires(rhythmicStruct != null);
Contract.Requires(this.Status != null);
this.Status.RhythmicStructure = rhythmicStruct; //// !!!!!!!!! attention!
if (this.Status.RhythmicStructure != null) {
if (this.Tones.Any()) { //// 2019/02 !?!
this.Tones.Clear();
}
var binStruct = this.Status.RhythmicStructure.BinaryStructure(true);
var binSchema = new BinarySchema(binStruct);
if (this.Status.RhythmicStructure.IsFromPreviousBar) {
this.SolveToneFromPreviousBar(givenLoudness);
}
this.AppendTonesAccordingToRhythm(givenLoudness, binSchema);
}
////2016 this.Status.ReflectChange();
}
///
/// Compose rhythm of lines in given bar.
///
public void FillWithRequestedRhythm() {
Contract.Requires(this.Status != null);
if (this.Status == null) {
return;
}
if (this.Tones.Any()) { //// 2019/02 !?!
this.Tones.Clear();
}
//// this.Status.RhythmicMotive = this.Status.RhythmicMotive;
if (this.Status.RhythmicStructure != null || this.Status.RhythmicMotive != null) {
var rhyStruct = this.DetermineRhythmicStructure(false);
var loudness = this.Status.Loudness;
this.FillWithRhythm(rhyStruct, loudness);
}
var addEmptyRange = this.Status.RhythmicStructure == null;
if (!addEmptyRange) {
return;
}
this.FillWithPause();
}
///
/// Fills the with pause.
///
public void FillWithPause() {
var range = new BitRange(this.Bar.Header.System.RhythmicOrder, 0, this.Bar.Header.System.RhythmicOrder);
//// 2019/02
var musicalPause = new MusicalPause(range, this.Bar.BarNumber);
//// var musicalStrike = new MusicalStrike(MusicalToneType.Empty, range, 0, this.Bar.BarNumber);
if (this.Status != null) {
musicalPause.InstrumentNumber = this.Status.Instrument.Number;
musicalPause.Staff = this.Status.Staff;
musicalPause.Voice = this.Status.Voice;
}
this.Tones.Add(musicalPause);
}
///
/// Fills the with rhythm of tones.
///
/// The given tones.
public void FillWithRhythmOfTones(MusicalStrikeCollection givenTones) {
var rorder = this.Bar.Header.System.RhythmicOrder;
this.Status.RhythmicStructure = new RhythmicStructure(rorder, givenTones); //// 2016 .MusicalTonesInBar(this.Number)//// 2014/01
}
///
/// Rhythmic structure in bar.
///
/// If set to true [fill empty].
///
/// Returns value.
///
public RhythmicStructure DetermineRhythmicStructure(bool fillEmpty) {
Contract.Requires(this.Status.RhythmicMotive != null);
if (this.Status.RhythmicStructure != null) {
return this.Status.RhythmicStructure;
}
int barIndex = 0;
//// why there is sometimes (after chuffle...) barNumber < this.Status.BarNumber ???
if (this.Bar.BarNumber >= this.Status.RhythmicMotiveStartBar) { //// && this.ComposedTrack.Status.BarNumber.HasValue
//// // here have to be bar-number of the rhythmical motive start
//// // this.BarNumber is bar number of the last change
barIndex = this.Bar.BarNumber - this.Status.RhythmicMotiveStartBar + 1;
}
if (barIndex < 1) {
return null;
}
//// 2016 - stop changes ? if (barIndex > this.RhythmicMotive.Length) { return null; }
var rhythmicOrder = this.Bar.Header.System.RhythmicOrder;
var rhyStructCode = this.Status.RhythmicMotive.RhythmicStructuralCodeForBar(barIndex);
if (string.IsNullOrEmpty(rhyStructCode)) {
rhyStructCode = fillEmpty ? "2" : "1";
}
var rsystem = RhythmicSystem.GetRhythmicSystem(RhythmicDegree.Structure, rhythmicOrder);
var rstruct = RhythmicStructure.GetNewRhythmicStructure(rsystem, rhyStructCode); //// rhyStructNumber
return rstruct;
}
///
/// Determines the melodic structure.
///
/// Returns value.
[UsedImplicitly]
public MelodicStructure DetermineMelodicStructure() {
Contract.Requires(this.Status.MelodicMotive != null);
int barIndex = 0;
//// why there is sometimes (after chuffle...) barNumber < this.Status.BarNumber ???
if (this.Bar.BarNumber >= this.Status.MelodicMotiveStartBar) { //// && this.ComposedTrack.Status.BarNumber.HasValue
//// // here have to be bar-number of the rhythmical motive start
//// // this.BarNumber is bar number of the last change
barIndex = this.Bar.BarNumber - this.Status.MelodicMotiveStartBar + 1;
}
if (barIndex < 1) {
return null;
}
//// 2016, see stop changes... if (barIndex > this.MelodicMotive.Length) { return null; }
var mms = this.Status.MelodicMotive.MelodicStructureInBar(barIndex);
return mms;
}
///
/// Completes the melodic tone.
///
/// The melodic tone.
public void CompleteMelodicTone(MusicalStrike musicalTone) {
Contract.Requires(musicalTone != null);
var line = this.MusicalLine;
MusicalStrike.CorrectBadBinding(line.LastTone, musicalTone);
//// mt.OrdinalIndex = this.MusicalTones.IndexOf(mt); ////?!
if (line.LastTone != null && !line.LastTone.IsEmpty) {
line.PenultTone = (MusicalTone)line.LastTone.Clone();
}
musicalTone.BarNumber = this.Bar.BarNumber;
if (musicalTone.BitRange != null) {
var loudness = this.DetermineLoudness(this.Status.RhythmicStructure, musicalTone.BitRange); //// (musicalBar.Number)
musicalTone.Loudness = loudness;
}
var status = this.Status;
musicalTone.InstrumentNumber = status.Instrument.Number;
//// musicalTone.Channel = (MidiChannel)status.InstrumentStatus.Channel;
musicalTone.Staff = status.Staff;
musicalTone.Voice = status.Voice;
//// mt.Type = MusicalToneType.Melodic;
}
///
/// Swaps the melodic with.
///
/// The element.
public void SwapMelodicWith(MusicalElement element) {
Contract.Requires(element != null);
var musicalOctave = element.Status.Octave;
element.Status.Octave = this.Status.Octave;
this.Status.Octave = musicalOctave;
var melodicType = element.Status.MelodicFunction;
element.Status.MelodicFunction = this.Status.MelodicFunction;
this.Status.MelodicFunction = melodicType;
var melodicStructure = element.Status.MelodicStructure;
element.Status.MelodicStructure = this.Status.MelodicStructure;
this.Status.MelodicStructure = melodicStructure;
}
#endregion
#region Public methods - Modification
///
/// Alter octaves by random.
///
public void RandomAlterOctave() {
if (this.Status.Octave == MusicalOctave.None) {
this.Status.Octave = MusicalOctave.OneLine;
return;
}
var increment = MathSupport.RandomNatural(2) == 0 ? 1 : -1;
var octave = (int)this.Status.Octave + increment;
if (octave >= (int)MusicalOctave.ThreeLine) {
octave = (int)MusicalOctave.ThreeLine;
}
if (octave <= (int)MusicalOctave.Small) {
octave = (int)MusicalOctave.Small;
}
this.Status.Octave = (MusicalOctave)octave;
}
///
/// Shifts the line octave.
///
/// The number of octaves.
public void ShiftOctave(int numberOfOctaves) {
if (this.Status.Octave == MusicalOctave.None) {
this.Status.Octave = MusicalOctave.OneLine;
return;
}
var n = (int)this.Status.Octave + numberOfOctaves;
n = Math.Min(n, (int)MusicalOctave.FiveLine);
n = Math.Max(n, (int)MusicalOctave.SubContra);
this.Status.Octave = (MusicalOctave)n;
}
#endregion
#region String representation
/// String representation of the object.
/// Returns value.
public override string ToString() {
var s = new StringBuilder();
s.AppendFormat(
" Bar {0} line {1} mel:{2} rhy:{3} R:{4}", this.Point.BarNumber, this.Point.LineIndex, this.Status.IsMelodicOriginal, this.Status.IsRhythmicOriginal, this.Status.RhythmicStructure != null ? this.Status.RhythmicStructure.ElementSchema : string.Empty);
return s.ToString();
}
///
/// To the progress string.
///
/// Returns value.
public string ToProgressString() {
var s = new StringBuilder();
s.AppendFormat(
" Bar {0} / Line {1}", this.Point.BarNumber, this.Point.LineIndex);
return s.ToString();
}
#endregion
#region Private methods
///
/// Solves the tone from previous bar.
///
/// The given loudness.
private void SolveToneFromPreviousBar(MusicalLoudness givenLoudness) {
var toneRange = this.Status.RhythmicStructure.OverrunRange();
if (toneRange == null) {
return;
}
//// MusicalStrike lastTone = ((Collection)this.MusicalTones).ElementAt(this.MusicalTones.Count()-1);
var lastTone = this.Tones.LastOrDefault();
if (lastTone == null) {
return;
}
lastTone.IsGoingToNextBar = MusicalSettings.Singleton.LongTones; //// true;
var tone = this.PrepareTone(givenLoudness, toneRange);
tone.IsFromPreviousBar = MusicalSettings.Singleton.LongTones; //// true;
this.Tones?.Add(tone);
//// this.Line.AddMusicalTone(musicalStrike);
}
///
/// Prepares the tone.
///
/// The given loudness.
/// The tone range.
///
/// Returns value.
///
private MusicalStrike PrepareTone(MusicalLoudness givenLoudness, BitRange toneRange) {
Contract.Requires(toneRange != null);
MusicalStrike tone;
var loudness = this.Status.RhythmicStructure != null && this.Status.RhythmicStructure.IsPauseStart(toneRange.BitFrom) ? MusicalLoudness.None : givenLoudness;
if (this.Status.LineType == MusicalLineType.Melodic) {
tone = new MusicalTone(null, toneRange, loudness, this.Bar.BarNumber);
}
else {
if (this.Status.RhythmicStructure != null) {
loudness = givenLoudness; //// (byte)MusicalLoudness.MeanLoudness; //// this.DetermineLoudness(musicalBar, this.Status.RhythmicStructure, toneRange);
}
tone = new MusicalStrike(MusicalToneType.Rhythmic, toneRange, loudness, this.Bar.BarNumber);
}
if (!this.Status.IsRhythmic) {
return tone;
}
//// 201508 if (this.Status.RhythmicStructure != null && musicalStrike.BitRange != null) {
//// loudness = this.TrackEngine.DetermineLoudness(musicalBar, this.Status.RhythmicStructure, musicalStrike.BitRange); } //// (musicalBar.Number)
tone.Loudness = loudness;
tone.InstrumentNumber = this.Status.Instrument.Number;
//// musicalStrike.Channel = (MidiChannel)this.Status.InstrumentStatus.Channel;
tone.Staff = this.Status.Staff;
tone.Voice = this.Status.Voice;
return tone;
}
///
/// Appends the tones according to rhythm.
///
/// The given loudness.
/// The bin schema.
private void AppendTonesAccordingToRhythm(MusicalLoudness givenLoudness, BinarySchema binSchema) {
Contract.Requires(binSchema != null);
var level = this.Status.RhythmicStructure.Level; //// not ToneLevel
BitRange toneRange = null;
for (byte i = 0; i < level; i++) {
if (this.Status.RhythmicStructure != null) {
if (i >= binSchema.Level) {
i = 0;
}
toneRange = binSchema.RangeAtLevel(i); // toneRange = [ MaskedBitRange];
}
if (toneRange == null || toneRange.Length == 0) {
continue;
}
var tone = this.PrepareTone(givenLoudness, toneRange);
if (this.Tones != null) {
tone.OrdinalIndex = this.Tones.Count;
this.Tones.Add(tone);
}
}
}
///
/// Assign Harmonic Modality.
///
/// Prevailing HarmonicStructure.
///
/// Returns value.
///
private HarmonicModality DetermineHarmonicModality(HarmonicStructure prevailingHarmonicStructure) {
Contract.Requires(this.Bar.HarmonicBar.HarmonicMotive != null);
//// Contract.Requires(musicalBar.HarmonicBar.HarmonicMotive.HarmonicCore != null);
//// if (musicalBar == null) { return null; }
HarmonicModality modality = null;
var minModalityLevel = MusicalSettings.Singleton.MinimalModalityLevel;
var modalization = MusicalSettings.Singleton.HarmonicModalization;
switch (modalization) {
//// 0. Chromatic only
case HarmonicModalizationType.Chromatic: {
//// modality = null;
break;
}
//// 1. Modality from structures in the bar after it disappears } (hstruct.Number & this.HarmonicModality.Number)==0)) (current settings)
case HarmonicModalizationType.Consecutive: {
if (prevailingHarmonicStructure != null) {
modality = prevailingHarmonicStructure.HarmonicModality;
if (modality == null || modality.Level < minModalityLevel || ((prevailingHarmonicStructure.Number & modality.Number) == 0)) {
modality = ((MusicalBar)this.Bar).HarmonicModalityFromStructures(MusicalSettings.Singleton.MinimalModalityLevel);
}
}
break;
}
//// 2. Forced from above
case HarmonicModalizationType.Forced:
modality = MusicalSettings.Singleton.ForcedModality;
break;
}
if (modality != null) {
return modality;
}
//// Chromatic modality is default value, when other assignments failed
modality = this.Bar.Header.System.HarmonicSystem.ChromaticModality;
return modality;
}
///
/// Corrects the loudness. According to dynamic rules.
///
/// The tone range.
/// The loudness.
///
/// Returns value.
///
private byte CorrectLoudness(BitRange toneRange, byte loudness) {
Contract.Requires(toneRange != null);
const byte consonanceLimit = 60;
if (toneRange.BitFrom == 0) {
loudness++;
}
else {
if (toneRange.Length > 1) {
loudness++;
}
if (toneRange.Length > 3) {
loudness++;
}
}
if (this.Status.LineType != MusicalLineType.Melodic || this.Bar == null) {
return loudness;
}
var cluster = ((MusicalBar)this.Bar).HarmonicClusterAtTick(toneRange.BitFrom);
if (cluster == null) {
return loudness;
}
var v = cluster.RealEnergy.Consonance; //// .FormalConsonance);
if (v < consonanceLimit) {
loudness++;
}
return loudness;
}
#endregion
}
}